package com.huitone.smspfm.redis.impl;

import java.net.SocketTimeoutException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.connection.DataType;

import com.alibaba.fastjson.JSONObject;
import com.huitone.smspfm.redis.BaseAbstractOpts;
import com.huitone.smspfm.redis.model.AppCanstant;

/**
 * 
* @Title: KeyOpts.java 
* @Package com.huitone.smspfm.redis.impl 
* @Description: TODO(用一句话描述该文件做什么) 
* @author ybliang   
* @date 2017年3月15日 下午2:08:02 
* @version V1.0
 */
public class KeyOpts extends BaseAbstractOpts<String, Object> {
	
	private static final Logger logger = LogManager.getLogger(KeyOpts.class);
	
	/**
	 * 尽量避免使用key的模糊匹配方法,在redis数据量较大时会严重影响性能
	 * @param pattern
	 * @return
	 */
	public Set<String> findKeys(String pattern) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		Set<String> result = new HashSet<String>();
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.keys(pattern);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "findKeys(String pattern)");
				json.put("pattern", pattern);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	public DataType type(String key) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		DataType result = null;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.type(key);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "type(String key)");
				json.put("key", key);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	/**
	 * 尽量避免使用key的模糊匹配方法,在redis数据量较大时会严重影响性能
	 * @param pattern
	 */
	public void delKeys(String pattern) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		do {
			try {
				curTryTimes ++;
				redisTemplate.delete(findKeys(pattern));
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "delKeys(String pattern)");
				json.put("pattern", pattern);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
	}
	
	public void delKey(String key) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		do {
			try {
				curTryTimes ++;
				redisTemplate.delete(key);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "delKey(String key)");
				json.put("key", key);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
	}
	
	public void expire(String key, long timeout, TimeUnit unit) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		do {
			try {
				curTryTimes ++;
				redisTemplate.expire(key, timeout, unit);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "expire(String key, long timeout, TimeUnit unit)");
				json.put("key", key);
				json.put("timeout", timeout);
				json.put("unit", unit.toString());
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
	}
	
}
